import Utils from "./utils/Utils";
import {UGroup} from "./index";


const {castArray, isNull, isNil, assign, defaultTo, isEmpty} = Utils

/**
 * UltimateCanvas
 * 容器对象
 * @author 如意虎头鞋
 */
class UltimateCanvas {
  private canvasDom: HTMLCanvasElement
  private canvasCtx: CanvasRenderingContext2D
  private option: Required<UComponent.UCanvasOption> = {width: 300, height: 300}
  
  /**
   * layers 中包含 (图层) 和 (组件)
   * @private
   */
  private parts: Part[] = []
  /**
   * 对于直接添加到canvas上的元素会默认添加到这个图层中
   * @private
   */
  private baseLayer: UGroup = new UGroup({name: 'base_group', zIndex: 0})

  constructor(canvasId: string, option?: UComponent.UCanvasOption) {
    this.initCanvas(canvasId)

    this.initOption(option)

    this.init()
  }

  private init() {
    this.parts.push(this.baseLayer)
  }
  
  setWidth(width: number): UltimateCanvas {
    this.canvasDom.width = width
    return this
  }

  setHeight(height: number): UltimateCanvas {
    this.canvasDom.height = height
    return this
  }

  setWidthAndHeight(width: number, height: number): UltimateCanvas {
    this.setWidth(width)
    this.setHeight(height)
    return this
  }

  getCanvasWidth(): number {
    return this.canvasDom.width
  }

  getCanvasHeight(): number {
    return this.canvasDom.height
  }

  getCanvasWidthAndHeight(): [number, number] {
    const width = this.getCanvasWidth()
    const height = this.getCanvasHeight()
    return [width, height]
  }

  get2DCtx(): CanvasRenderingContext2D {
    return this.canvasCtx
  }

  /**
   * @description 获取 canvas dom 引用
   */
  getCanvasDom(): HTMLCanvasElement {
    return this.canvasDom
  }
  
  /**
   * @description 添加部件
   * @param {Part[]} components 部件列表 （组件 | 图层）
   */
  add(...components: Part[]) {
    components.forEach(part => {
      if (part instanceof UGroup) {
        this.parts.push(part)
      } else {
        this.baseLayer.add(part)
      }

      this.parts.sort((a, b) => a.zIndex - b.zIndex)
    })
  }
  
  /**
   *  @description 移除组件
   * @param components 组件或者图层
   */
  remove(components: Part | Part[]) {
    const _components = castArray<Part>(components)
    console.log(_components)
  }
  
  /**
   * @description 通过名称移除组件
   * @param partName
   */
  removeByName(partName: string | string[]) {
    const _partName = castArray<string>(partName)
    if (isEmpty(_partName)) return
    
    // todo 删除操作
  }

  // todo
  findPart() {}
  // todo
  findPartByName() {}
  
  /**
   * @description 清理画布所有内容 恢复空白
   */
  clear() {
    this.get2DCtx().clearRect(0, 0, this.getCanvasWidth(), this.getCanvasHeight())
    return this
  }

  /**
   * 重绘canvas
   * @private
   */
  render(): UltimateCanvas {
    this.clear()
    
    const ctx = this.get2DCtx()
    this.parts.forEach((layerOrComponent) => layerOrComponent.draw(ctx))
    return this
  }

  /**
   * @description 初始化 canvas
   * @param canvasId
   * @private
   */
  private initCanvas(canvasId: string) {
    const canvasDom = document.getElementById(canvasId) as HTMLCanvasElement
    if (isNull(canvasDom)) throw new ReferenceError(`未能查找到ID为${canvasId}的dom结构`)

    this.canvasDom = canvasDom

    // 兼容性检查
    if (isNil(canvasDom.getContext)) throw new ReferenceError("抱歉，您的设备不支持Canvas")
    this.canvasCtx = canvasDom.getContext('2d') as CanvasRenderingContext2D
  }

  /**
   * 初始化配置项
   * @param option
   * @private
   */
  private initOption(option?: UComponent.UCanvasOption) {
    this.option = assign(this.option, defaultTo(option, {})) as Required<UComponent.UCanvasOption>

    const {width, height} = this.option
    this.setWidthAndHeight(width, height)
  }
}


export default UltimateCanvas
